import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:im_app/im/util/ImSingleton.dart';

import '../../dao/ImCollectDao.dart';
import '../../dao/ImFileDao.dart';
import '../../dao/ImSessionDao.dart';
import '../../pojo/Enums.dart';
import '../../pojo/ImPojo.dart';
import '../../service/ImMessageSendService.dart';
import '../../util/LoggerUtil.dart';
import '../../util/UiUtil.dart';
import '../sub/FileBrowsePage.dart';
import 'BaseBloc.dart';

final class FileBrowseCubit extends BaseBloc<FileBrowseEvent, FileBrowseState> {

  final _logger = createLogger();

  FileBrowseCubit(ImSession session) : super(FileBrowseState.init(session)) {
    on<FileBrowseLoadFileEvent>((event, emit) {
      _loadFiles(state, event.index);
    });
    on<FileBrowseAddFileEvent>((event, emit) {
      _addFile(state, event.file);
    });
    on<FileBrowseRemoveFileEvent>((event, emit) {
      _removeFile(state, event.file);
    });

    on<FileBrowseAddCollectFileEvent>((event, emit) {
      _addCollectFile(state, event.file);
    });
    on<FileBrowseRemoveCollectFileEvent>((event, emit) {
      _removeCollectFile(state, event.file);
    });
    on<FileBrowseLoadSendEvent>((event, emit) {
      _sendFiles(state, event.context, event.fileViewType);
    });

  }

  _loadFiles(FileBrowseState oldState, int index) async {
    if (index == 0) {
      var fileDao = ImFileDao();
      var files = await fileDao.getFiles(0, 200);
      var state = oldState.copy(fileLoadingState: LoadingState.success, searchFiles: files);
      emit(state);
    } else if (index == 1) {
      var collectDao = ImCollectDao();
      var userId = ImSingleton.getInstance().session.userId;
      var collects = await collectDao.getCollects(userId!, null, [ImMessageType.File, ImMessageType.Audio], 200);
      var collectFiles = collects.map((collect)=>_toImFile(collect)).toList();
      emit(oldState.copy(collectFileLoadingState: LoadingState.success, searchCollectFiles: collectFiles));
    } else if (index == 2) {
      emit(oldState.copy(systemFileLoadingState: LoadingState.success));
    } else {
      _logger.e('FileBrowse not supply the index: $index');
    }
  }

  _addFile(FileBrowseState oldState, ImFile file) {
    if (!oldState.selectedFiles.contains(file)) {
      var selectedFiles = List.of(oldState.selectedFiles);
      selectedFiles.add(file);
      var state = oldState.copy(selectedFiles: selectedFiles);
      emit(state);
    }
  }

  _removeFile(FileBrowseState oldState, ImFile file) {
    if (oldState.selectedFiles.contains(file)) {
      var selectedFiles = List.of(oldState.selectedFiles);
      selectedFiles.remove(file);
      var state = oldState.copy(selectedFiles: selectedFiles);
      emit(state);
    }
  }

  _addCollectFile(FileBrowseState oldState, ImFile file) {
    if (!oldState.selectedCollectFiles.contains(file)) {
      var selectedFiles = List.of(oldState.selectedCollectFiles);
      selectedFiles.add(file);
      var state = oldState.copy(selectedCollectFiles: selectedFiles);
      emit(state);
    }
  }

  _removeCollectFile(FileBrowseState oldState, ImFile file) {
    if (oldState.selectedCollectFiles.contains(file)) {
      var selectedCollectFiles = List.of(oldState.selectedCollectFiles);
      selectedCollectFiles.remove(file);
      var state = oldState.copy(selectedCollectFiles: selectedCollectFiles);
      emit(state);
    }
  }

  _sendFiles(FileBrowseState oldState, BuildContext context, FileViewType fileViewType) async {
    emit(oldState.copy(isSending: true));

    try {
      var session = oldState.imSession;

      var messageService = ImMessageSendService();
      var messages = <ImMessage>[];
      var files = <ImFile>[];
      if (fileViewType == FileViewType.file) {
        files = oldState.selectedFiles;
      } else {
        files = oldState.selectedCollectFiles;
      }
      for (var uiFile in files) {
        var message = await messageService.buildMessage(session!, uiFile.path, ImMessageType.File, null);
        messages.add(message);
      }
      UiUtil.uiAddMessages(messages);

      UiUtil.uiChangeSession(session);

      await messageService.sendMessage([session], messages);

      Navigator.of(context).pop();

      UiUtil.showSnackBar(context, '消息发送成功');
    } catch (error, stackTrace) {
      _logger.e('[send message error]', error: error, stackTrace: stackTrace);
    }
  }

  ImFile _toImFile(ImCollect collect) {
    collect.initContent();
    var message = collect.message;
    message?.initMessageExt();
    var messageExt = message?.messageExt;
    var file = ImFile(currentUserId: collect.userId, sessionId: collect.sessionId, messageId: collect.messageId,
      fileName: messageExt?.originalName??'', fileSize: messageExt?.size??0, isRelativePath: messageExt?.remote??true,
      path: message?.content??'', md5: messageExt?.md5??'');
    file.id = collect.id;
    return file;
  }
}

final class FileBrowseState extends Equatable {

  final ImSession imSession;
  final LoadingState fileLoadingState;
  final LoadingState collectFileLoadingState;
  final LoadingState systemFileLoadingState;
  final List<ImFile> searchFiles;
  final List<ImFile> searchCollectFiles;
  final List<ImFile> selectedFiles;
  final List<ImFile> selectedCollectFiles;
  final bool isSending;

  const FileBrowseState._({
    this.fileLoadingState = LoadingState.loading,
    this.collectFileLoadingState = LoadingState.loading,
    this.systemFileLoadingState = LoadingState.loading,
    this.searchFiles = const <ImFile>[],
    this.searchCollectFiles = const <ImFile>[],
    this.selectedFiles = const <ImFile>[],
    this.selectedCollectFiles = const <ImFile>[],
    required this.imSession,
    this.isSending = false,
  });

  FileBrowseState copy({
        List<ImFile>? searchFiles,
        List<ImFile>? searchCollectFiles,
        LoadingState? fileLoadingState,
        LoadingState? collectFileLoadingState,
        LoadingState? systemFileLoadingState,
        List<ImFile>? selectedFiles,
        List<ImFile>? selectedCollectFiles,
        bool? isSending,
    }) {
    return FileBrowseState._(
      imSession: imSession,
      searchFiles: searchFiles ?? this.searchFiles,
      searchCollectFiles: searchCollectFiles ?? this.searchCollectFiles,
      fileLoadingState: fileLoadingState ?? this.fileLoadingState,
      collectFileLoadingState: collectFileLoadingState ?? this.collectFileLoadingState,
      systemFileLoadingState: systemFileLoadingState ?? this.systemFileLoadingState,
      selectedFiles: selectedFiles ?? this.selectedFiles,
      selectedCollectFiles: selectedCollectFiles ?? this.selectedCollectFiles,
      isSending: isSending ?? this.isSending,
    );
  }

  const FileBrowseState.init(ImSession imSession) : this._(imSession: imSession);

  @override
  List<Object?> get props => [imSession, fileLoadingState, collectFileLoadingState, searchFiles, searchCollectFiles,
    systemFileLoadingState, selectedFiles, selectedCollectFiles, isSending];

}

abstract class FileBrowseEvent {}
class FileBrowseLoadFileEvent extends FileBrowseEvent {
  final int index;
  FileBrowseLoadFileEvent(this.index);
}
class FileBrowseLoadCollectFileEvent extends FileBrowseEvent {}
class FileBrowseAddFileEvent extends FileBrowseEvent {
  final ImFile file;
  FileBrowseAddFileEvent(this.file);
}
class FileBrowseRemoveFileEvent extends FileBrowseEvent {
  final ImFile file;
  FileBrowseRemoveFileEvent(this.file);
}

class FileBrowseAddCollectFileEvent extends FileBrowseEvent {
  final ImFile file;
  FileBrowseAddCollectFileEvent(this.file);
}
class FileBrowseRemoveCollectFileEvent extends FileBrowseEvent {
  final ImFile file;
  FileBrowseRemoveCollectFileEvent(this.file);
}
class FileBrowseLoadSendEvent extends FileBrowseEvent {
  final FileViewType fileViewType;
  final BuildContext context;
  FileBrowseLoadSendEvent(this.context, this.fileViewType);
}